package org.jeecg.modules.workflow.convert.task;

import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.collection.CollectionUtils;
import org.jeecg.common.util.json.JsonUtils;
import org.jeecg.common.workflow.vo.task.instance.BpmProcessInstancePageItemRespVO;
import org.jeecg.common.workflow.vo.task.instance.BpmProcessInstanceRespVO;
import org.jeecg.modules.workflow.entity.BpmProcessDefinitionExt;
import org.jeecg.modules.workflow.entity.BpmProcessInstanceExt;
import org.jeecg.modules.workflow.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO;
import org.jeecg.modules.workflow.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO;
import org.springframework.stereotype.Service;

import java.util.*;


@Service
public class BpmProcessInstanceConvertImpl implements BpmProcessInstanceConvert {

    private static final TypeReference<Map<String, Object>> typeReference = new TypeReference<Map<String, Object>>(){};
    private static final TypeReference<List<String>> listTypeReference = new TypeReference<List<String>>(){};


    @Override
    public void copyTo(ProcessInstance from, BpmProcessInstanceExt to) {
        if ( from == null ) {
            return;
        }

        to.setCreateTime( from.getStartTime() );
        if ( from.getStartUserId() != null ) {
            to.setStartUserId(from.getStartUserId() );
        }
        else {
            to.setStartUserId( null );
        }
        to.setName( from.getName() );
        to.setProcessInstanceId( from.getProcessInstanceId() );
        to.setProcessDefinitionId( from.getProcessDefinitionId() );
    }

    @Override
    public void copyTo(ProcessDefinition from, BpmProcessInstanceExt to) {
        if ( from == null ) {
            return;
        }

        to.setName( from.getName() );
        to.setCategory( from.getCategory() );
    }

    @Override
    public List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExt> list) {
        if ( list == null ) {
            return null;
        }

        List<BpmProcessInstancePageItemRespVO> list1 = new ArrayList<BpmProcessInstancePageItemRespVO>( list.size() );
        for ( BpmProcessInstanceExt bpmProcessInstanceExtDO : list ) {
            list1.add( convert( bpmProcessInstanceExtDO ) );
        }

        return list1;
    }

    @Override
    public List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks) {
        if ( tasks == null ) {
            return null;
        }

        Map<String,Task> uniqueDefinedTaskMap = new LinkedHashMap<>();
        for ( Task task : tasks ) {
            //list.add( taskToTask( task ) );
            String taskDefinitionKey = task.getTaskDefinitionKey();
            if(!uniqueDefinedTaskMap.containsKey(taskDefinitionKey)){
                uniqueDefinedTaskMap.put(taskDefinitionKey, task);
            }
        }
        List<BpmProcessInstancePageItemRespVO.Task> list = CollectionUtils.convertList(uniqueDefinedTaskMap.values(), task -> taskToTask( task ));
        return list;
    }

    @Override
    public BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExt bean) {
        if ( bean == null ) {
            return null;
        }

        BpmProcessInstancePageItemRespVO bpmProcessInstancePageItemRespVO = new BpmProcessInstancePageItemRespVO();

        bpmProcessInstancePageItemRespVO.setId( bean.getProcessInstanceId() );
        bpmProcessInstancePageItemRespVO.setName( bean.getName() );
        bpmProcessInstancePageItemRespVO.setProcessDefinitionId( bean.getProcessDefinitionId() );
        bpmProcessInstancePageItemRespVO.setCategory( bean.getCategory() );
        bpmProcessInstancePageItemRespVO.setStatus( bean.getStatus() );
        bpmProcessInstancePageItemRespVO.setResult( bean.getResult() );
        bpmProcessInstancePageItemRespVO.setCreateTime( bean.getCreateTime() );
        bpmProcessInstancePageItemRespVO.setEndTime( bean.getEndTime() );

        return bpmProcessInstancePageItemRespVO;
    }

    @Override
    public BpmProcessInstanceExt convert(org.flowable.engine.runtime.ProcessInstance bean) {
        if ( bean == null ) {
            return null;
        }

        BpmProcessInstanceExt bpmProcessInstanceExtDO = new BpmProcessInstanceExt();

        bpmProcessInstanceExtDO.setProcessInstanceId( bean.getId() );
        bpmProcessInstanceExtDO.setCreateTime( bean.getStartTime() );
        if ( bean.getStartUserId() != null ) {
            bpmProcessInstanceExtDO.setStartUserId(bean.getStartUserId());
        }
        if(StringUtils.isEmpty(bean.getName())){
            bpmProcessInstanceExtDO.setName( bean.getProcessDefinitionName() );
        }else{
            bpmProcessInstanceExtDO.setName( bean.getName() );
        }
        bpmProcessInstanceExtDO.setProcessDefinitionId( bean.getProcessDefinitionId() );

        return bpmProcessInstanceExtDO;
    }

    @Override
    public BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean) {
        if ( bean == null ) {
            return null;
        }

        BpmProcessInstanceRespVO bpmProcessInstanceRespVO = new BpmProcessInstanceRespVO();

        bpmProcessInstanceRespVO.setId( bean.getId() );
        bpmProcessInstanceRespVO.setName( bean.getName() );
        bpmProcessInstanceRespVO.setEndTime( bean.getEndTime() );
        bpmProcessInstanceRespVO.setBusinessKey( bean.getBusinessKey() );

        return bpmProcessInstanceRespVO;
    }

    @Override
    public void copyTo(BpmProcessInstanceExt from, BpmProcessInstanceRespVO to) {
        if ( from == null ) {
            return;
        }

        to.setName( from.getName() );
        to.setCategory( from.getCategory() );
        to.setStatus( from.getStatus() );
        to.setResult( from.getResult() );
        to.setCreateTime( from.getCreateTime() );
        to.setEndTime( from.getEndTime() );
        if ( to.getFormVariables() != null ) {
            Map<String, Object> map = JsonUtils.parseObject(from.getFormVariables(), typeReference);
            if ( map != null ) {
                to.getFormVariables().clear();
                to.getFormVariables().putAll( map );
            }
            else {
                to.setFormVariables( null );
            }
        }
        else {
            if(StringUtils.isNotEmpty(from.getFormVariables())){
                Map<String, Object> map = JsonUtils.parseObject(from.getFormVariables(), typeReference);
                if ( map != null ) {
                    to.setFormVariables( new HashMap<String, Object>( map ) );
                }
            }
        }
    }

    @Override
    public BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean) {
        if ( bean == null ) {
            return null;
        }

        BpmProcessInstanceRespVO.ProcessDefinition processDefinition = new BpmProcessInstanceRespVO.ProcessDefinition();

        processDefinition.setId( bean.getId() );

        return processDefinition;
    }

    @Override
    public void copyTo(BpmProcessDefinitionExt from, BpmProcessInstanceRespVO.ProcessDefinition to) {
        if ( from == null ) {
            return;
        }

        to.setFormType( from.getFormType() );
        to.setFormId( from.getFormId() );
        to.setFormConf( from.getFormConf() );
        if ( to.getFormFields() != null ) {
            List<String> list = JsonUtils.parseObject(from.getFormFields(), listTypeReference);
            if ( list != null ) {
                to.getFormFields().clear();
                to.getFormFields().addAll( list );
            }
            else {
                to.setFormFields( null );
            }
        }
        else {
            if(from.getFormFields() != null){
                List<String> list = JsonUtils.parseObject(from.getFormFields(), listTypeReference);
                if ( list != null ) {
                    to.setFormFields( new ArrayList<String>( list ) );
                }
            }
        }
        to.setFormCustomCreatePath( from.getFormCustomCreatePath() );
        to.setFormCustomViewPath( from.getFormCustomViewPath() );
    }

    @Override
    public BpmProcessInstanceRespVO.User convert2(LoginUser bean) {
        if ( bean == null ) {
            return null;
        }

        BpmProcessInstanceRespVO.User user = new BpmProcessInstanceRespVO.User();

        user.setId( bean.getId() );
        user.setNickname( bean.getRealname());
        /*if(bean.getDept() != null){
            user.setDeptId( bean.getDept().getDeptId() );
        }*/

        return user;
    }

    @Override
    public void copyTo(ProcessInstance from, BpmMessageSendWhenProcessInstanceRejectReqDTO to) {
        if ( from == null ) {
            return;
        }

        to.setProcessInstanceName( from.getName() );
        to.setProcessInstanceId( from.getProcessInstanceId() );
        if ( from.getStartUserId() != null ) {
            to.setStartUserId( from.getStartUserId());
        }
        else {
            to.setStartUserId( null );
        }
    }

    @Override
    public BpmMessageSendWhenProcessInstanceApproveReqDTO convert2(org.flowable.engine.runtime.ProcessInstance processInstance) {
        if ( processInstance == null ) {
            return null;
        }

        BpmMessageSendWhenProcessInstanceApproveReqDTO bpmMessageSendWhenProcessInstanceApproveReqDTO = new BpmMessageSendWhenProcessInstanceApproveReqDTO();

        bpmMessageSendWhenProcessInstanceApproveReqDTO.setProcessInstanceId( processInstance.getId() );
        bpmMessageSendWhenProcessInstanceApproveReqDTO.setProcessInstanceName( processInstance.getName() );
        if ( processInstance.getStartUserId() != null ) {
            bpmMessageSendWhenProcessInstanceApproveReqDTO.setStartUserId( processInstance.getStartUserId());
        }

        return bpmMessageSendWhenProcessInstanceApproveReqDTO;
    }

    protected BpmProcessInstancePageItemRespVO.Task taskToTask(Task task) {
        if ( task == null ) {
            return null;
        }

       BpmProcessInstancePageItemRespVO.Task task1 = new BpmProcessInstancePageItemRespVO.Task();

        task1.setId( task.getId() );
        task1.setName( task.getName() );

        return task1;
    }
}
